///******************** NG.Respate(C)  **********************************
//* 产品名称: Respate 科技
//* 文件名称: signal.c
//* 程序作者: 雷帕特公司(南宫子萍)
//* 程序版本: V1.1														   
//* 编制日期: 2019/1/29
//* 功能描述: tftp服务器
//* QQ:	2085827949
//**********************************************************************/
#include "lap_tftp.h"
#include "LapSocket.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <stdlib.h>

/*********************************************************************************
** 函数名称: tftp_get
** 功能描述: 从服务器获取文件
** 输入参数: name: 文件名          
** 输出参数: None.
** 返回参数: return response .
**********************************************************************************/
int tftp_get(const char* name)
{
	short block;
	int len = 0;
	int allSize =0;
	int bSize = tConfig.block+1024;
	char* buff= (char*)malloc(bSize);
	char*temp = buff;	// 防止buff首地址改变

	int breakFlag = 0; 			// 退出状态标志
	struct sockaddr_in s_addr; 	// 
	struct sockaddr_in c_addr; 	//  
	int cfd = Lap_UDP_Socket4(tConfig.port,tConfig.ip,&s_addr);	// 连接服务器
	if(cfd < 0 ) return -1;
	if(name==NULL) return -2;

	char fname[512]={0};
	sprintf(fname,"%s/%s",tConfig.download,name);
	int fd = open(fname,O_TRUNC|O_CREAT|O_RDWR,S_IRWXU);
	if(fd<0) goto eerfd;


	// 读请求码
	tftpPackage pack=
	{
		.prw =
		{
			.opcode = TFTP_RRQ,
			.name = name,
			.mode = tConfig.mode
		}
	};

	while(1)
	{
		buff = temp;			// 防止buff首地址改变
		memset(buff,0,bSize);
		len = tftp_Pack2Stream(&pack,buff,0);
		sendto(cfd,buff,len,0,(struct sockaddr_in*)&s_addr,sizeof(struct sockaddr_in ));
		// test_printf(buff,len);
		if(breakFlag == 1) break;

		// 接收数据
		len = recvfrom(cfd,buff,bSize,0,(struct sockaddr_in*)&s_addr,&len);
		len = tftp_Stream2Pack(&pack,buff,len);
		//tftp_packInfo(stdout,&pack,len);
		block = pack.pdata.block;

		if(len < tConfig.block) breakFlag = 1;	// 接收完毕 退出标志置1(发送最后ACK)
		if(pack.pdata.opcode!= TFTP_DATA) break;// 返回值不为数据操作码

		write(fd,pack.pdata.data,len);	// 保存数据到磁盘
		allSize += len;

		// 送应答
		pack.pack.opcode = TFTP_ACK;
		pack.pack.block = block; 
	}

eerfd:
	// 错误处理
	tftp_packInfo(stdout,&pack,allSize);

	free(temp);
	return allSize;	// 返回接收总字节数
}

/*********************************************************************************
** 函数名称: tftp_put
** 功能描述: 上传文件到服务器
** 输入参数: name: 文件名        
** 输出参数: None.
** 返回参数: return response .
**********************************************************************************/
int tftp_put(char* name)
{
	short block = 0;
	int len = 0;
	int allSize =0;
	int bSize = tConfig.block+1024;
	char* buff= (char*)malloc(bSize);
	char*temp = buff;	// 防止buff首地址改变
	

	int breakFlag = 0; 			// 退出状态标志
	struct sockaddr_in s_addr; 	// 
	struct sockaddr_in c_addr; 	//  
	int cfd = Lap_UDP_Socket4(tConfig.port,tConfig.ip,&s_addr);	// 连接服务器
	if(cfd < 0 ) return -1;
	if(name==NULL) return -2;

	int fd = open(name,O_RDONLY);
	if(fd<0) goto eerfd;

	// 读请求码
	tftpPackage pack=
	{
		.prw =
		{
			.opcode = TFTP_WRQ,
			.name = name,
			.mode = tConfig.mode
		}
	};

	// 请求写数据
	len = tftp_Pack2Stream(&pack,buff,0);
	sendto(cfd,buff,len,0,(struct sockaddr_in*)&s_addr,sizeof(struct sockaddr_in ));

	while(1)
	{
		buff = temp;			// 防止buff首地址改变
		memset(buff,0,bSize);

		// 接收ACk
		len = recvfrom(cfd,buff,bSize,0,(struct sockaddr_in*)&s_addr,&len);
		len = tftp_Stream2Pack(&pack,buff,len);
		//tftp_packInfo(stdout,&pack,len);

		if(pack.pdata.opcode!= TFTP_ACK) break; // 返回值不为ACK
		if(block != pack.pack.block) break;		// 返回值不为ACK
		if(breakFlag == 1) break;				// 收到最后一次应答

		len = read(fd,&buff[4],tConfig.block);	// 磁盘读数据

		if(len < tConfig.block) breakFlag = 1;	// 最后一帧数据 退出标志置1(发送最后ACK)
		allSize += len;

		// 发送数据
		pack.pack.opcode = TFTP_DATA;
		pack.pack.block = ++block; 
		tftp_Pack2Stream(&pack,buff,0);
		sendto(cfd,buff,len+4,0,(struct sockaddr_in*)&s_addr,sizeof(struct sockaddr_in ));
	}


eerfd:
	// 错误处理
	tftp_packInfo(stdout,&pack,allSize);


	free(temp);
	close(fd);
	return allSize;	// 返回接收总字节数
}




#if 0
int main()
{
	tftpConfig config =
	{	
		.port = 69,
		.block = 521,
		.ip = "192.168.20.240",
		.mode = TFTP_MODE_NETAS,
		.download = "./bin_dir"
	};

	//tftp_printfConfig(&tConfig);
	tftp_config(&config);
	// tftp_get("jd.jpg");
	// tftp_put("Makefile");
}
#endif

